package config

import (
	"bytes"
	"errors"
	"fmt"
	"path/filepath"
	"ruoyi-go-echo-ddd/internal/infrastructure/persistence/prop"
	"ruoyi-go-echo-ddd/internal/infrastructure/utils"
	"sync"

	"github.com/rs/zerolog"
	"github.com/spf13/viper"
)

// ReadConfig 读取配置
//
// 参数
//
//	-path：配置路径
//	-name：配置文件名(不包括后缀)
//	-configType：配置文件路径
//
// 返回
//
//	-viper：*viper.Viper
func ReadConfig(path, name, configType string) *viper.Viper {
	viper.AddConfigPath(path)
	viper.SetConfigName(name)
	viper.SetConfigType(configType)

	if err := viper.ReadInConfig(); err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("viper读取配置文件错误")
		panic(fmt.Errorf("viper config read error===%w", err))
	}
	return viper.GetViper()
}

// FullConfig 统一配置结构体
type FullConfig struct {
	Server     *prop.ServerConfig     `mapstructure:"server"`
	Postgres   *prop.PostgresqlConfig `mapstructure:"postgres"`
	Mysql      *prop.MysqlConfig      `mapstructure:"mysql"`
	Minio      *prop.MinioConfig      `mapstructure:"minio"`
	Redis      *prop.RedisConfig      `mapstructure:"redis"`
	RSA        *prop.RsaConfig        `mapstructure:"rsa"`
	Cache      *prop.CacheConfig      `mapstructure:"cache"`
	JWT        *prop.JwtConfig        `mapstructure:"jwt"`
	Nacos      *prop.NacosConfig      `mapstructure:"nacos"`
	RequestUrl *prop.RequestUrlConfig `mapstructure:"request"`
}

// 全局配置定义
var (
	ViperConfig      *viper.Viper          // 全局Viper配置
	ServerConfig     prop.ServerConfig     // 全局服务配置
	PostgresConfig   prop.PostgresqlConfig // 全局postgres配置
	MysqlConfig      prop.MysqlConfig      // 全局mysql配置
	MinIoConfig      prop.MinioConfig      // 全局minio配置
	RedisConfig      prop.RedisConfig      // 全局redis配置
	RsaConfig        prop.RsaConfig        // 全局RSA密钥配置
	CacheConfig      prop.CacheConfig      // 全局缓存键等配置
	JwtConfig        prop.JwtConfig        // 全局JWT配置
	NacosConfig      prop.NacosConfig      // 全局nacos配置
	RequestUrlConfig prop.RequestUrlConfig // 全局请求白名单配置
)

var globalConfigOnce = sync.OnceValue(func() error {
	configPath := "config"
	currentPath, err := utils.GetCurrentPath()
	if err != nil {
		zerolog.DefaultContextLogger.Info().Msgf("viper获取目录错误===%v", err)
	} else {
		// 如果是Docker中，这里获取当前的目录为/，这里在Dockerfile中设置了目录/app/config
		if currentPath == "/" {
			configPath = filepath.Join("/app", configPath)
		} else {
			configPath = filepath.Join(currentPath, "config")
		}
	}

	zerolog.DefaultContextLogger.Info().Msgf("viper配置路径===%s", configPath)
	ViperConfig = ReadConfig(configPath, "application", "yml")

	if ViperConfig == nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("viper读取配置失败")
		return errors.New("配置文件初始化失败")
	}

	var fullConfig FullConfig

	// 一次性解析所有配置
	if err := ViperConfig.Unmarshal(&fullConfig); err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("viper解析配置失败")
		return err
	}

	zerolog.DefaultContextLogger.Info().Msgf("所有配置===\n%s", utils.ToJsonFormat(fullConfig))

	if fullConfig.Server != nil {
		ServerConfig = *fullConfig.Server
	}

	if fullConfig.Postgres != nil {
		PostgresConfig = *fullConfig.Postgres
	}

	if fullConfig.Mysql != nil {
		MysqlConfig = *fullConfig.Mysql
	}

	if fullConfig.Minio != nil {
		MinIoConfig = *fullConfig.Minio
	}

	if fullConfig.Redis != nil {
		RedisConfig = *fullConfig.Redis
	}

	if fullConfig.Cache != nil {
		CacheConfig = *fullConfig.Cache
	}

	if fullConfig.JWT != nil {
		JwtConfig = *fullConfig.JWT
	}

	if fullConfig.Nacos != nil {
		NacosConfig = *fullConfig.Nacos
	}

	if fullConfig.RSA != nil {
		RsaConfig = *fullConfig.RSA
	}

	if fullConfig.RequestUrl != nil {
		RequestUrlConfig = *fullConfig.RequestUrl
	}
	return nil
})

// InitGlobalConfig 初始化全局配置
func InitGlobalConfig() error {
	return globalConfigOnce()
}

// ParseConfig 解析配置
//
// 参数:
//
//	-raw: 需要解析的内容
//	-format: 配置格式 (支持json、yaml、properties等，需与Nacos控制台中格式一致)
//
// 返回值:
//
//	-*T: 解析后的配置对象指针
//	-error: 错误信息（当配置获取失败或解析失败时返回）
func ParseConfig[T any](raw string, format string) (*T, error) {
	v := viper.New()
	v.SetConfigType(format)

	// 从字符串加载配置
	if err := v.ReadConfig(bytes.NewBuffer([]byte(raw))); err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("读取配置错误")
		return nil, err
	}

	// 反序列化到结构体
	var t T
	if err := v.Unmarshal(&t); err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("反序列化到结构错误")
		return nil, err
	}

	return &t, nil
}
